package com.watchmen.wechat.pay;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.watchmen.wechat.config.WeChatConfig;
import com.watchmen.wechat.util.HttpRequest;
import com.watchmen.wechat.util.MD5Util;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
 * @author kk
 * @Description 微信相关
 */
@Component
public class WeChatPay {
	
	@Autowired
	WeChatConfig weChatConfig;
	
	@Autowired
	MD5Util mD5Util;
	
	@Autowired
	HttpRequest httpRequest;
	
	
	
	/**
	 * 微信扫码支付
	 * @param amount 金额
	 * @param body 描述
	 * @param openid 微信openid
	 * @return
	 */
	@SuppressWarnings("unused")
	public JSONObject scanningPay(String amount,String body,String openid){
		JSONObject parse = null;
		try {
			TreeMap<String, Object> params = new TreeMap<>();
			// 支付的商品名称    
			params.put("body", body);
			// 商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】  
			params.put("out_trade_no", "F"+IdUtil.createSnowflake(1, 1).nextId());
			// 支付金额  
			params.put("total_fee", amount);
			// 商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】  
			params.put("out_trade_no", IdUtil.simpleUUID());
			// openid
			params.put("openid", openid);
			// 交易类型
			params.put("trade_type", weChatConfig.getTradeTypeNative());
		
			String returnJson = weChatInitialization(params);
			parse = (JSONObject) JSONUtil.parse(returnJson);
			
			return  parse;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return parse;
	}
	
	
	/**
	 * 微信JSAPI支付
	 * @param amount 金额
	 * @param body 描述
	 * @param openid 微信openid
	 * @return
	 */
	public TreeMap<String, Object> JSAPIPay(String amount,String body,String openid){
		// 返回给前端
		TreeMap<String, Object> map = MapUtil.newTreeMap(null);
		
		JSONObject parse = null;
		try {
			TreeMap<String, Object> params = new TreeMap<>();
			// 支付的商品名称    
			params.put("body", body);
			// 商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】  
			params.put("out_trade_no", "F"+IdUtil.createSnowflake(1, 1).nextId());
			// 支付金额  
			params.put("total_fee", amount);
			// 商户订单号【备注：每次发起请求都需要随机的字符串，否则失败。】  
			params.put("out_trade_no", IdUtil.simpleUUID());
			// openid
			params.put("openid", openid);
			// 交易类型
			params.put("trade_type", weChatConfig.getTradeTypeJSAPI());
			
			String returnJson = weChatInitialization(params);
			parse = (JSONObject) JSONUtil.parse(returnJson);
			
			String xml = parse.getStr("xml");
			JSONObject parseObj = JSONUtil.parseObj(xml);
			
			// 预付款id
			String prepayId = parseObj.getStr("prepay_id");
			
			// appId
			map.put("appId", weChatConfig.getAppID());
			// 时间戳
			map.put("timeStamp", System.currentTimeMillis());
			// 随机字符串
			map.put("nonceStr", IdUtil.simpleUUID());
			// 预支付Id
			map.put("package", prepayId);
			// 加密类型
			map.put("signType", weChatConfig.getWeChatMD5Sign());
			// 签名
			map.put("paySign", mD5Util.createSign(CharsetUtil.UTF_8, map, weChatConfig.getWeChatApiKey()));
			
			return  map;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}
	
	
	
	/**
	 * 微信支付参数初始化
	 * @param params 输入参数
	 * @param payType 支付类型
	 * @return
	 */
	private String weChatInitialization(TreeMap<String, Object> params){
		
		// 获取ip地址
		LinkedHashSet<String> localIpv4s = cn.hutool.core.net.NetUtil.localIpv4s();
		String localIpv4 = "127.0.0.1";
		if(localIpv4s.size() > 0){
			Integer count = 0;
			for (String ip : localIpv4s) {
				 count++;
				 if(count == 2){
					 localIpv4 = ip;
				 }
			}
		}
		
		try {
			// 公众账号ID
			params.put("appid", weChatConfig.getAppID());
			// 商户号
			params.put("mch_id", weChatConfig.getWeChatMerchant());
			// 随机字符串  
			params.put("nonce_str", IdUtil.createSnowflake(1, 1).nextId());
			// 通知地址(回调地址)
			params.put("notify_url", weChatConfig.getWeChatCallbackUrl());
			// 客户端主机 ip 
			params.put("spbill_create_ip", localIpv4);
			
			// 生成签名
			String createSign = mD5Util.createSign(CharsetUtil.UTF_8, params, weChatConfig.getWeChatApiKey());
			params.put("sign", createSign);
			
			// 转换成xml格式，在请求微信接口
			String createXml = getRequestXml(params);
			
			// 调用微信统一下单接口
			String doHttpsJson_HttpClient = httpRequest.doHttpsJson_HttpClient(weChatConfig.getWeChatOrderUrl(),
					"POST", createXml.toString());
			// 把微信返回的xml格式转化为json串
			JSONObject parseFromXml = JSONUtil.parseFromXml(doHttpsJson_HttpClient);
			
			return parseFromXml.toString();
			
		} catch (Exception e) {
			throw new RuntimeException("初始化参数失败!");
		}
	}
	
	
	
	
	
	/**
	 * 解析微信回调数据
	 * @param request
	 * @return
	 */
	public Map<String, Object> payResult(HttpServletRequest request){
		Map<String, Object> map = new HashMap<String, Object>();
		StringBuffer sb = new StringBuffer();
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
		
			String line = "";
			while((line = br.readLine()) != null){
				sb.append(line);
			}
			
			JSONObject parseFromXml = JSONUtil.parseFromXml(sb.toString());
			String xml = parseFromXml.getStr("xml");
			
			String resultCode = JSONUtil.parseObj(xml).getStr("result_code");
			String returnCode = JSONUtil.parseObj(xml).getStr("return_code");
			
			if("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)){
				map = (Map<String, Object>) parseFromXml.getObj("xml");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return map;
	}
	
	
	
	
	/**  
     * @author chenp 
     * @Description：将请求参数转换为xml格式的string  
     * @param parameters  请求参数  
     * @return  
     */    
    public  String getRequestXml(SortedMap<String, Object> parameters) {    
        StringBuffer sb = new StringBuffer();    
        sb.append("<xml>");    
        parameters.forEach((k,v) -> {
        	 if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {    
                 sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");    
             } else {    
                 sb.append("<" + k + ">" + v + "</" + k + ">");    
             }    
        });
        sb.append("</xml>");    
        return sb.toString();    
    } 

}
